/*
 *  Axolotl - Alternate persistence for Grails
 *  Copyright (C) 2008  Juanjo García Latre
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.googlecode.axolotl.query;

import java.io.Serializable;


/**
 * Specifies the expected order for the results of a <code>Query</code>.
 * <code>Order</code> instances can be chained, so the next instance is
 * applied when the previous one yields equals for a certain pair of entities.
 * Each <code>Order</code> instance has one and only one <code>PropertyName</code>
 * instance. 
 *
 * @author juanjo
 */
public class Order implements Serializable, Cloneable {
	
	public static final char PROPERTYNAME_SEPARATOR = ',';

	private PropertyName propertyName;
	private boolean ascendant = true;
	private Order next;


	/**
	 * 
	 */
	public Order() {
	}


	/**
	 * 
	 */
	public Order(String order) {
		int pos = order.indexOf(PROPERTYNAME_SEPARATOR);

		if (pos >= 0) {
			propertyName = new PropertyName( order.substring(0, pos).trim() );
			next = new Order( order.substring(pos + 1).trim() );
		}
		else {
			propertyName = new PropertyName(order);
		}
	}


	/**
	 * 
	 */
	public Order(String order, boolean ascendant) {
		this(order);
		setAscendant(ascendant);
	}


	/**
	 *
	 */
	public Order(PropertyName propertyName) {
		this(propertyName, true);
	}


	/**
	 *
	 */
	public Order(PropertyName propertyName, boolean ascendant) {
		setProperty(propertyName);
		setAscendant(ascendant);
	}


	/**
	 *
	 */
	public PropertyName getProperty() {
		return propertyName;
	}


	/**
	 * 
	 */
	public void setProperty(PropertyName propertyName) {
		this.propertyName = propertyName;
	}


	/**
	 *
	 */
	public boolean isAscendant() {
		return ascendant;
	}


	/**
	 *
	 */
	public void setAscendant(boolean ascendant)	{
		this.ascendant = ascendant;
	}


	/**
	 * 
	 */
	public Order getNext() {
		return next;
	}


	/**
	 * 
	 */
	public void setNext(Order next)	{
		this.next = next;
	}

	/*-------------------------------------------------------------------------*/

	/**
	 *
	 */
	public <R> R accept(QueryVisitor<R> visitor) {
		return visitor.visit(this);
	}


	/**
	 *
	 */
	public boolean equals(Object o) {      
		if (o == null || !(o instanceof Order)) {
			return false;
		}
		else {
			Order other = (Order) o;
			return other.propertyName.equals(this.propertyName) &&
					other.ascendant == this.ascendant &&
					(other.next == null && this.next == null || 
							other.next != null && other.next.equals(this.next));
		}
	}


	/**
	 *
	 */
	public Object clone() {
		try {
			return super.clone();
		}
		catch (CloneNotSupportedException exc) {
			return null;
		}
	}


	/**
	 *
	 */
	public String toString() {
		return accept(Criterion.STRING_RENDERER).toString();
	}

}
